package org.dromara.utils;

import cn.hutool.core.map.MapUtil;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineNode;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.dromara.genealogy.domain.TocItem;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author YWQ
 * @date 2025/7/16 10:37
 * @description PDF文件工具类
 */
public class PdfUtil {

    /**
     * 将PDF的指定页面转换为图片
     *
     * @param url     PDF文件地址
     * @param dpi         图片分辨率
     * @param imageFormat 图片格式（如"png", "jpg"）
     * @param pages       要提取的页码列表（基于1的索引）
     * @return 页码对应图片字节数组列表
     */
    public static Map<Integer, byte[]> convertPdfPagesToImages(String url, int dpi, String imageFormat, List<Integer> pages) throws IOException {
        Map<Integer, byte[]> resByteMap = MapUtil.newHashMap();
        try (PDDocument document = PDDocument.load(new URL(url).openStream())) {
            PDFRenderer renderer = new PDFRenderer(document);
            for (int pageIndex : pages) {
                //注意：PDF页码从0开始
                pageIndex = pageIndex - 1;
                // 验证页码有效性
                if (pageIndex < 0 || pageIndex >= document.getNumberOfPages()) {
                    continue;
                }
                // 渲染页面为图像
                BufferedImage image = renderer.renderImageWithDPI(pageIndex, dpi);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ImageIO.write(image, imageFormat, baos);
                resByteMap.put(pageIndex + 1, baos.toByteArray());
            }
        }
        return resByteMap;
    }

    /**
     * 从PDF输入流中提取目录项（书签）信息。
     *
     * @param inputStream PDF文件的输入流
     * @return 包含所有目录项的列表
     * @throws RuntimeException 当读取或解析PDF过程中发生IO异常时抛出
     */
    public static List<TocItem> extractTocItems(InputStream inputStream) {
        try (PDDocument document = PDDocument.load(inputStream)) {
            List<TocItem> TocItems = new ArrayList<>();
            PDOutlineNode outline = document.getDocumentCatalog().getDocumentOutline();

            // 如果存在文档大纲（即书签），则遍历并提取所有顶层书签
            if (outline != null) {
                PDOutlineItem current = outline.getFirstChild();
                while (current != null) {
                    extractTocItemItems(current, TocItems, 1);
                    current = current.getNextSibling();
                }
            }

            return TocItems;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 递归提取指定书签及其子书签的信息，并添加到结果列表中。
     *
     * @param item 当前处理的书签项
     * @param TocItems 存放提取结果的列表
     * @param level 当前书签所在的层级（从1开始）
     */
    private static void extractTocItemItems(PDOutlineItem item, List<TocItem> TocItems, int level) {
        if (item == null){
            return;
        }

        // 获取书签标题
        String title = item.getTitle();

        // 获取书签指向的页码
        int pageNumber = getPageNumber(item);

        // 添加到书签列表
        TocItems.add(new TocItem(title, pageNumber, level));

        // 处理子书签
        /*PDOutlineItem child = item.getFirstChild();
        if (child != null) {
            extractTocItemItems(child, TocItems, level + 1);
        }*/

        // 处理同级书签
        /*PDOutlineItem sibling = item.getNextSibling();
        if (sibling != null) {
            extractTocItemItems(sibling, TocItems, level);
        }*/
    }

    /**
     * 获取指定书签指向的页码。
     *
     * @param item 书签项
     * @return 书签指向的页码（从1开始），如果无法获取则返回-1
     */
    private static int getPageNumber(PDOutlineItem item) {
        try {
            PDDestination destination = item.getDestination();
            if (destination instanceof PDPageDestination) {
                PDPageDestination pageDestination = (PDPageDestination) destination;
                return pageDestination.retrievePageNumber() + 1;
            }
        } catch (IOException e) {
            System.err.println("获取书签页码时出错: " + e.getMessage());
        }
        return -1;
    }

    public static void main(String[] args) throws IOException {
        String path = "D:\\project\\zszhsystem\\word\\标书制作二期开发文档\\标书模板\\电信招标文件正文-副本.pdf";
        InputStream inputStream = Files.newInputStream(Paths.get(path));

        // 提取书签信息
        List<TocItem> TocItems = extractTocItems(inputStream);

        // 输出书签信息
        System.out.println("=== PDF书签信息 ===");
        for (TocItem TocItem : TocItems) {
            System.out.printf("级别%d: %s -> 页码: %d%n",
                    TocItem.getLevel(), TocItem.getTitle(), TocItem.getPageNumber());
        }
    }

}
